home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Software Vault: The Gold Collection
/
Software Vault - The Gold Collection (American Databankers) (1993).ISO
/
cdr08
/
arcdib20.zip
/
YOURCOMP.PAS
< prev
Wrap
Pascal/Delphi Source File
|
1993-06-17
|
11KB
|
276 lines
{ This is an example of exporting your own compression algorithm into ARCDIB
using a Turbo Pascal DLL. You can use this code as a shell by replacing
the "YouCompress" and "YourDeCompress" functions with your own algorithms
for compression and decompression respectively. The function exported by
the DLL is "MyComp".
function MyComp(var IMAGEHANDLE: THandle;
var BITSSIZE: LongInt;
COMPRESS: Boolean): Boolean ; export;
Its name and parameters must not change since ARCDIB expects it that way.
As you can see, the function returns TRUE or FALSE depending on its sucess
- determined by you. The three parameters are:
IMAGEHANDLE: a Windows Global Handle to a memory block containing either
the uncompressed or compressed bytes of the bitmap image.
BITSSIZE: the size of the bitmap bytes ("bits") before being
compressed and the size of the compressed bits when
expanding.
COMPRESS: TRUE if compressing, FALSE if decompressing. If compressing,
IMAGEHANDLE refers to a block of uncompressed bitmap "bits"
- the same as to "bits" of a Windows DIB. If decompressing,
then IMAGEHANDLE refers to the block of memory returned as
a result of a previous compression.
THE CONCEPT IS THIS:
Upon entry into "MyComp" you obtain a pointer to the memory block referred
to by IMAGEHANDLE. You then create another global Handle of size BITSSIZE
to use as output of your compression/decompression routine. Obtain a
pointer to this NewHandle with GlobalLock. Then, you pass each byte
in IMAGEHANDLE (in this case, one at a time) to either YourCompress or
YourDeCompress routines depending on the COMPRESS flag. In each of those
routines, you write the output to the new memory block you created
referred to by NewHandle. Finally, you reallocate NewHandle to the size
resulting from the compression/decompression (ie keep track of the number
of bytes written) and get rid the passed in IMAGEHANDLE with GlobalFree
and reassign it to Newhandle. Always pass the resulting size of the
compressed (or expanded) bytes in BITSSIZE!
Keep the following in mind:
1. This alorithm ASSUMES the result of the compression will require
a smaller block of memory than the original. For decompression,
the result should equal the original (obiviously) and the
GlobalReAlloc call is actually redundant because in both cases
you create Newhandle using the original (uncompressed) size.
2. You must keep track of the number of bytes written to the new
handle in order to determine its new size for reallocation.
3. Don't forget to "unlock" the new handle before returning from
the function.
4. If the function returns FALSE, ARCDIB flags the bitmap as being
in compressed form and will therefore call MyComp again to
uncompress the "bits" before displaying.
5. If you return FALSE during compression, ARCDIB will just
assume something went wrong in your compression and EXPECTS
IMAGEHANDLE refer to the same block of uncompressed bytes that
it did before the call! This could be disastorous if you somehow
corrupt the original data so be careful not to. Worse yet, on
decompression, returning FALSE leaves ARCDIB on a limb because,
presumably, it passed in successfully compressed data and you
are now telling it that there's no way back...we're doomed.
6. Keep in mind that if the size of the bitmap is greater that
64K, you must make your code aware of the segment boundries
that you'll eventually cross reading and (possibly) writing
from/to the memory blocks. This is illustrated in the example
by creating a variant record type for a special far pointer
that can be safely incremented using a Windows call to AHINC().
***** Thanks to Tom Swam (the Charles Petzold of TPW) and his book
"Turbo Pascal for Windows 3.0 Programming" for this and MANY
other useful tricks.
6. When compressing/decompressing a bitmap in ARCDIB, a status
box appears showing percent completion. In your case, I have
no way of knowing this info so the box just kind of sits
there and says "Please wait..". In the future, I'll provide
some type of Callback function so that you can update the
status yourself - or least the OPTION to, since most compression
purest loaf the idea of delaying their algorithm unecessarily.
7. Again, the library (DLL) name MUST remain "YourComp" and the
compression function name MUST remain "MyComp" with the SAME
parameters and exported index.
Sine Labore Nihil...
Brendan Daunt
BETTER MAPS
(619) 598-1323
76307,2411
}
{***************************************************************************}
library YourComp; { Don't change this name }
uses WinTypes, WinProcs;
{ Windows function for calculating pointer offsets safely }
Procedure AHIncr; far; external 'KERNEL' index 114;
{ Variant record type for a far pointer to step through memory blocks that
may cross segment boundries. }
Type
LongType = record
case word of
0: (Ptr: Pointer);
1: (Long: LongInt);
2: (Lo: Word; Hi: Word);
end;
{ Global variables }
Var h, { Temporary handle }
NewHandle: THandle; { New handle refers to compressed "bits" }
OldBits, { Pointer to memory block in IMAGEHANDLE }
NewBits : Pointer; { Pointer to memory block in NewHandle }
NewSize : LongInt; { Resulting size of NewHandle after compression }
{ These are dummy procedures (stubs) provided to illustrate how you might
implement your own compress/decompress algorithms.
They are called from the exported function "MyComp" with a Byte type
parameter which represents an uncompressed/compressed byte in the
original IMAGEHANDLE passed to "MyComp".
Be sure to write the output of either function to the global memory
block in NewHandle and also keep track of the numbers of bytes written }
Var
ToBits,
ToStart,
ToAddr : LongType; { Special far pointer records }
procedure YourCompress(InByte: Byte);
{}
Begin
{ ...compress InByte somehow }
ToAddr.Hi := ToBits.Hi + ( ToStart.Hi * Ofs(AHIncr));
ToAddr.Lo := ToStart.LO;
Byte(ToAddr.Ptr^) := InByte;
Inc(ToStart.Long);
Inc(NewSize);
End;
procedure YourDeCompress(InByte: Byte);
{}
Begin
{ ...decompress InByte somehow }
ToAddr.Hi := ToBits.Hi + ( ToStart.Hi * Ofs(AHIncr));
ToAddr.Lo := ToStart.LO;
Byte(ToAddr.Ptr^) := InByte;
Inc(ToStart.Long);
Inc(NewSize);
End;
{ This is the only function exported by YourComp.DLL - header and
results must remain the same (see above). }
function MyComp(var IMAGEHANDLE: THandle;
var BITSSIZE: LongInt;
COMPRESS: Boolean) : Boolean ; export;
{}
Var
OneByte : Byte; { Holds a byte to be compressed/decompressed }
ImageSize, { Size of IMAGEHANDLE }
OldPtrOffSet: LongInt; { Pointer offset into IMAGEHANDLE }
FromBits,
FromStart,
FromAddr : LongType; { Special far pointer records }
Begin
MessageBox(GetActiveWindow, 'Dummy compress DLL for instructional purposes only.', 'YourComp.DLL', mb_IconExclamation);
MyComp := False;
NewSize := 0; { Contains the number of bytes written to NewHandle }
{ Get a pointer to the original handle }
OldBits := GlobalLock(IMAGEHANDLE);
If OldBits = nil Then
Begin
MessageBox(GetActiveWindow, 'OldBits = nil', 'MyComp ERROR',
mb_TaskModal or mb_Ok);
Exit;
End;
{ Create new memory block (NewHandle) - same size as uncompressed block }
NewHandle := GlobalAlloc(gmem_Moveable or gmem_ZeroInit, BITSSIZE);
If NewHandle = 0 Then
Begin
MessageBox(GetActiveWindow, 'NewHandle = 0', 'MyComp ERROR',
mb_TaskModal or mb_Ok);
Exit;
End;
{ Get a pointer to the new handle }
NewBits := GlobalLock(NewHandle);
If NewBits = nil Then
Begin
MessageBox(GetActiveWindow, 'NewBits = nil', 'MyComp ERROR',
mb_TaskModal or mb_Ok);
GlobalFree(NewHandle);
Exit;
End;
FromStart.Long := 0; { Initial pointer offset into IMAGEHANDLE }
FromBits.Ptr := OldBits; { Use LongType pointer for segment "awareness" }
ToStart.Long := 0; { Initial pointer offset into NewHandle }
ToBits.Ptr := NewBits; { Use LongType pointer for segment "awareness" }
{ Process each byte in IMAGEHANDLE }
ImageSize := GlobalSize(IMAGEHANDLE);
For OldPtrOffset := 0 to ImageSize-1 Do
Begin
{ Calculate the pointer offset }
FromAddr.Hi := FromBits.Hi + ( FromStart.Hi * Ofs(AHIncr));
FromAddr.Lo := FromStart.LO;
{ Get a byte from the original memory block in IMAGEHANDLE }
OneByte := Byte(FromAddr.Ptr^);
{ Now call your compression or decompression routine with OneByte }
If Compress Then
YourCompress(OneByte) { procedure of your choice for compression }
Else
YourDeCompress(OneByte); { procedure of your choice for decompression }
{ Increment the pointer offset }
Inc(FromStart.Long);
End; { For each byte in IMAGEHANDLE }
{ Unlock the NewHandle and attempt to reallocate it with new size }
GlobalUnlock(NewHandle);
h := GlobalReAlloc(NewHandle, NewSize, gmem_Moveable or gmem_ZeroInit);
if (h <> 0) Then
Begin
GlobalUnlock(IMAGEHANDLE);
GlobalFree(IMAGEHANDLE); { Get rid of original handle to "bits" }
NewHandle := h; { Assign NewHandle to reallocated block}
End
Else { GlobalReAlloc failed - abort }
Begin
GlobalFree(NewHandle); { Free the new handle }
MessageBox(GetActiveWindow, 'Could realloc NewHandle', 'MyComp ERROR',
mb_TaskModal or mb_Ok);
Exit;
End;
{ Success }
BITSSIZE := NewSize;
ImageHandle := NewHandle;
MyComp := True;
End; { MyComp }
{- List exported routines }
exports
MyComp index 3; { Export MyComp with index of 3 }
BEGIN
END. { YourComp DLL }